﻿// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using Microsoft.Extensions.Localization;

namespace BootstrapBlazor.Components;

/// <summary>
/// 
/// </summary>
public partial class DateTimeRange
{
    /// <summary>
    /// 获得 组件 DOM 实例
    /// </summary>
    private ElementReference PickerRange { get; set; }

    /// <summary>
    /// 获得 组件样式名称
    /// </summary>
    private string? ClassString => CssBuilder.Default("datetime-range")
        .AddClass("disabled", IsDisabled)
        .AddClassFromAttributes(AdditionalAttributes)
        .Build();

    /// <summary>
    /// 获得 组件弹窗样式名称
    /// </summary>
    private string? BodyClassString => CssBuilder.Default("datetime-range-body")
        .AddClass("d-none", !IsShown)
        .Build();

    /// <summary>
    /// 获得 组件弹窗位置
    /// </summary>
    private string? PlacementString => CssBuilder.Default()
        .AddClass("top", Placement == Placement.Top)
        .AddClass("bottom", Placement == Placement.Bottom)
        .AddClass("left", Placement == Placement.Left)
        .AddClass("right", Placement == Placement.Right)
        .Build();

    private string? BarStyleString => CssBuilder.Default()
        .AddClass("padding-right: 16px;", AllowNull)
        .Build();

    /// <summary>
    /// 获得 组件小图标样式
    /// </summary>
    private string? DateTimePickerIconClassString => CssBuilder.Default("datetime-range-input-icon")
        .AddClass("disabled", IsDisabled)
        .Build();

    /// <summary>
    /// 获得 用户选中的时间范围
    /// </summary>
    internal DateTimeRangeValue SelectedValue { get; } = new DateTimeRangeValue();

    private DateTime StartValue { get; set; }

    private string? StartValueString => (Value == null || Value.Start == DateTime.MinValue) ? null : Value.Start.ToString(DateFormat);

    private DateTime EndValue { get; set; }

    private string? EndValueString => (Value == null || Value.End == DateTime.MinValue) ? null : Value.End.ToString(DateFormat);

    [NotNull]
    private string? StartPlaceHolderText { get; set; }

    [NotNull]
    private string? EndPlaceHolderText { get; set; }

    [NotNull]
    private string? SeparateText { get; set; }

    [NotNull]
    private string? DateFormat { get; set; }

    /// <summary>
    /// 获得/设置 清空按钮文字
    /// </summary>
    [Parameter]
    [NotNull]
    public string? ClearButtonText { get; set; }

    /// <summary>
    /// 获得/设置 今天按钮文字
    /// </summary>
    [Parameter]
    [NotNull]
    public string? TodayButtonText { get; set; }

    /// <summary>
    /// 获得/设置 确定按钮文字
    /// </summary>
    [Parameter]
    [NotNull]
    public string? ConfirmButtonText { get; set; }

    /// <summary>
    /// 获得/设置 弹窗位置 默认为 Auto
    /// </summary>
    [Parameter]
    public Placement Placement { get; set; } = Placement.Auto;

    /// <summary>
    /// 获得/设置 是否显示本组件默认为 false 不显示
    /// </summary>
    [Parameter]
    public bool IsShown { get; set; }

    /// <summary>
    /// 获得/设置 是否允许为空 默认为 true
    /// </summary>
    [Parameter]
    public bool AllowNull { get; set; } = true;

    /// <summary>
    /// 获得/设置 是否显示今天按钮 默认为 false
    /// </summary>
    [Parameter]
    public bool ShowToday { get; set; }

    /// <summary>
    /// 获得/设置 是否显示快捷侧边栏 默认不显示
    /// </summary>
    [Parameter]
    public bool ShowSidebar { get; set; }

    /// <summary>
    /// 获得/设置 侧边栏快捷选项集合
    /// </summary>
    [Parameter]
    [NotNull]
    public IEnumerable<DateTimeRangeSidebarItem>? SidebarItems { get; set; }

    /// <summary>
    /// 点击确认按钮回调委托方法
    /// </summary>
    [Parameter]
    public Func<DateTimeRangeValue, Task>? OnConfirm { get; set; }

    /// <summary>
    /// 点击清空按钮回调委托方法
    /// </summary>
    [Parameter]
    public Func<DateTimeRangeValue, Task>? OnClearValue { get; set; }

    [Inject]
    [NotNull]
    private IStringLocalizer<DateTimeRange>? Localizer { get; set; }

    /// <summary>
    /// OnParametersSet 方法
    /// </summary>
    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        Value ??= new DateTimeRangeValue();

        StartValue = Value.Start;
        EndValue = Value.End;

        if (StartValue == DateTime.MinValue) StartValue = DateTime.Now;
        if (EndValue == DateTime.MinValue) EndValue = StartValue.AddMonths(1);

        SelectedValue.Start = StartValue;
        SelectedValue.End = EndValue;

        StartPlaceHolderText ??= Localizer[nameof(StartPlaceHolderText)];
        EndPlaceHolderText ??= Localizer[nameof(EndPlaceHolderText)];
        SeparateText ??= Localizer[nameof(SeparateText)];

        ClearButtonText ??= Localizer[nameof(ClearButtonText)];
        ConfirmButtonText ??= Localizer[nameof(ConfirmButtonText)];
        TodayButtonText ??= Localizer[nameof(TodayButtonText)];

        DateFormat ??= Localizer[nameof(DateFormat)];

        if (StartValue.ToString("yyyy-MM") == EndValue.ToString("yyyy-MM"))
        {
            StartValue = StartValue.AddMonths(-1);
        }

        if (SidebarItems == null)
        {
            SidebarItems = new DateTimeRangeSidebarItem[]
            {
                    new DateTimeRangeSidebarItem{ Text = Localizer["Last7Days"], StartDateTime = DateTime.Today.AddDays(-7), EndDateTime = DateTime.Today },
                    new DateTimeRangeSidebarItem{ Text = Localizer["Last30Days"], StartDateTime = DateTime.Today.AddDays(-30), EndDateTime = DateTime.Today },
                    new DateTimeRangeSidebarItem{ Text = Localizer["ThisMonth"], StartDateTime = DateTime.Today.AddDays(1- DateTime.Today.Day), EndDateTime = DateTime.Today.AddDays(1 - DateTime.Today.Day).AddMonths(1).AddDays(-1) },
                    new DateTimeRangeSidebarItem{ Text = Localizer["LastMonth"], StartDateTime = DateTime.Today.AddDays(1- DateTime.Today.Day).AddMonths(-1), EndDateTime = DateTime.Today.AddDays(1- DateTime.Today.Day).AddDays(-1) },
            };
        }
    }

    /// <summary>
    /// OnAfterRender 方法
    /// </summary>
    /// <param name="firstRender"></param>
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (firstRender)
        {
            await JSRuntime.InvokeVoidAsync(PickerRange, "bb_datetimeRange");
        }
    }

    private async Task OnClickSidebarItem(DateTimeRangeSidebarItem item)
    {
        SelectedValue.Start = item.StartDateTime;
        SelectedValue.End = item.EndDateTime;
        StartValue = item.StartDateTime;
        EndValue = StartValue.AddMonths(1);
        await ClickConfirmButton();
    }

    /// <summary>
    /// 点击 清除按钮调用此方法
    /// </summary>
    /// <returns></returns>
    private async Task ClickClearButton()
    {
        Value = new DateTimeRangeValue();
        if (ValueChanged.HasDelegate)
        {
            await ValueChanged.InvokeAsync(Value);
        }
        if (OnValueChanged != null)
        {
            await OnValueChanged(Value);
        }
        if (OnClearValue != null) await OnClearValue(Value);

        StartValue = DateTime.Today;
        EndValue = StartValue.AddMonths(1);
        SelectedValue.Start = DateTime.MinValue;
        SelectedValue.End = DateTime.MinValue;
    }

    /// <summary>
    /// 点击 确认时调用此方法
    /// </summary>
    private async Task ClickTodayButton()
    {
        SelectedValue.Start = DateTime.Today;
        SelectedValue.End = DateTime.Today;
        StartValue = DateTime.Today;
        EndValue = StartValue.AddMonths(1);
        await ClickConfirmButton();
    }

    /// <summary>
    /// 点击 确认时调用此方法
    /// </summary>
    private async Task ClickConfirmButton()
    {
        if (SelectedValue.End == DateTime.MinValue)
        {
            if (SelectedValue.Start < DateTime.Now)
            {
                SelectedValue.End = DateTime.Now;
            }
            else
            {
                SelectedValue.End = SelectedValue.Start;
                SelectedValue.Start = DateTime.Now;
            }
        }
        Value = SelectedValue;
        if (Value.End.Hour == 0)
        {
            Value.End = Value.End.AddDays(1).AddSeconds(-1);
        }
        if (ValueChanged.HasDelegate)
        {
            await ValueChanged.InvokeAsync(Value);
        }
        if (OnValueChanged != null)
        {
            await OnValueChanged(Value);
        }
        if (OnConfirm != null) await OnConfirm(Value);
        await JSRuntime.InvokeVoidAsync(PickerRange, "bb_datetimeRange", "hide");
    }

    /// <summary>
    /// 更新年时间方法
    /// </summary>
    /// <param name="d"></param>
    internal void UpdateStart(DateTime d)
    {
        StartValue = StartValue.AddYears(d.Year - StartValue.Year).AddMonths(d.Month - StartValue.Month);
        EndValue = StartValue.AddMonths(1);
        StateHasChanged();
    }

    /// <summary>
    /// 更新年时间方法
    /// </summary>
    /// <param name="d"></param>
    internal void UpdateEnd(DateTime d)
    {
        EndValue = EndValue.AddYears(d.Year - EndValue.Year).AddMonths(d.Month - EndValue.Month);
        StartValue = EndValue.AddMonths(-1);
        StateHasChanged();
    }

    /// <summary>
    /// 更新值方法
    /// </summary>
    /// <param name="d"></param>
    internal void UpdateValue(DateTime d)
    {
        if (SelectedValue.End == DateTime.MinValue)
        {
            if (d < SelectedValue.Start)
            {
                SelectedValue.End = SelectedValue.Start;
                SelectedValue.Start = d;
            }
            else
            {
                SelectedValue.End = d;
            }
        }
        else
        {
            SelectedValue.Start = d;
            SelectedValue.End = DateTime.MinValue;
        }

        if (d.Year < StartValue.Year || d.Month < StartValue.Month)
        {
            UpdateStart(d);
        }
        else if (d.Month > EndValue.Month)
        {
            UpdateEnd(d);
        }
        else
        {
            StateHasChanged();
        }
    }
}
